<Project>
  <Import Project="$(WasmCommonTargetsPath)WasmApp.Common.targets" />

  <UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.WasiAppBuilder" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />

  <PropertyGroup>
    <PrepareForWasmBuildNativeDependsOn>
      _CheckToolchainIsExpectedVersion;
      _PrepareForWasiBuildNative;
      $(PrepareForWasmBuildNativeDependsOn)
    </PrepareForWasmBuildNativeDependsOn>

    <WasmLinkDotNetDependsOn>
      $(WasmLinkDotNetDependsOn);
      _WasiLinkDotNet;
    </WasmLinkDotNetDependsOn>

    <WasmGenerateAppBundleDependsOn>
      $(WasmGenerateAppBundleDependsOn);
      _GetWasiGenerateAppBundleDependencies;
      _WasiGenerateAppBundle;
      _GenerateRunWasmtimeScript;
      _WasmGenerateNodeScripts;
    </WasmGenerateAppBundleDependsOn>

    <SelfContained Condition="'$(IsWasiProject)' == 'true'">true</SelfContained>

    <!-- Temporarily `false`, till sdk gets a fix for supporting the new file -->
    <WasmEmitSymbolMap Condition="'$(WasmEmitSymbolMap)' == '' and '$(RunAOTCompilation)' != 'true'">false</WasmEmitSymbolMap>
    <TrimMode Condition="'$(TrimMode)' == ''">partial</TrimMode>

    <WasmRunWasmOpt Condition="'$(WasmRunWasmOpt)' == ''">false</WasmRunWasmOpt>

    <!--<WasiBundleAssemblies Condition="'$(WasiBundleAssemblies)' == ''">true</WasiBundleAssemblies>-->
    <!-- FIXME: rename to WasmHost?? -->
    <!--<WasiRunner Condition="'$(WasiRunner)' == ''">wasmtime</WasiRunner>-->
  </PropertyGroup>

  <ItemGroup>
    <_BoolPropertiesThatTriggerRelinking Include="WasmEnableSIMD" DefaultValueInRuntimePack="false" />
    <!--<_BoolPropertiesThatTriggerRelinking Include="WasmEnableExceptionHandling" DefaultValueInRuntimePack="true" />-->
  </ItemGroup>

  <Target Name="_GetWasiGenerateAppBundleDependencies">
    <ItemGroup Condition="'$(InvariantGlobalization)' == 'true' or '$(WasmSingleFileBundle)' == 'true'">
      <ReferenceCopyLocalPaths Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat" />
    </ItemGroup>
    <ItemGroup Condition="'$(WasmBuildNative)' == 'true'">
      <ReferenceCopyLocalPaths Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.wasm" />
    </ItemGroup>
    <ItemGroup Condition="'$(WasmBuildNative)' != 'true'">
      <!-- Add the default ones when we don't compile one -->
      <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.wasm"/>
    </ItemGroup>

    <ItemGroup Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmSingleFileBundle)' != 'true'">
      <WasmIcuDataFileNames Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"/>
      <WasmNativeAsset Include="@(WasmIcuDataFileNames)"/>
    </ItemGroup>
  </Target>

  <!-- FIXME: make this similar to what browser targets has -->
  <Target Name="_WasiGenerateAppBundle"
          Inputs="@(_WasmAssembliesInternal);@(WasmNativeAsset)"
          Outputs="$(WasmAppDir)\.stamp"
          Condition="'$(WasmGenerateAppBundle)' == 'true'">

    <PropertyGroup>
      <_WasmOutputSymbolsToAppBundle Condition="'$(CopyOutputSymbolsToPublishDirectory)' == 'true' and '$(_IsPublishing)' == 'true'">true</_WasmOutputSymbolsToAppBundle>
      <_WasmOutputSymbolsToAppBundle Condition="'$(_WasmOutputSymbolsToAppBundle)' == ''">false</_WasmOutputSymbolsToAppBundle>
    </PropertyGroup>

    <WasiAppBuilder
      AppDir="$(WasmAppDir)"
      Assemblies="@(_WasmAssembliesInternal)"
      MainAssemblyName="$(WasmMainAssemblyFileName)"
      IsSingleFileBundle="$(WasmSingleFileBundle)"
      HostConfigs="@(HostConfig)"
      RuntimeArgsForHost="@(WasmMonoRuntimeArgs)"
      DefaultHostConfig="$(DefaultWasmHostConfig)"
      InvariantGlobalization="$(InvariantGlobalization)"
      SatelliteAssemblies="@(_WasmSatelliteAssemblies)"
      IcuDataFileNames="@(WasmIcuDataFileNames)"
      FilesToIncludeInFileSystem="@(WasmFilesToIncludeInFileSystem)"
      ExtraFilesToDeploy="@(WasmExtraFilesToDeploy)"
      NativeAssets="@(WasmNativeAsset)"
      OutputSymbolsToAppBundle="$(_WasmOutputSymbolsToAppBundle)"
      RuntimeConfigJsonPath="$(_WasmRuntimeConfigFilePath)"
      />
  </Target>

  <Import Project="$(MSBuildThisFileDirectory)WasiSdk.Defaults.props" />
  <Target Name="_SetupWasiSdk" BeforeTargets="_SetupToolchain">
    <PropertyGroup>
      <_ToolchainMissingPaths Condition="'$(_ToolchainMissingPaths)' == '' and ('$(WasiClang)' == '' or !Exists('$(WasiClang)'))">%24(WasiClang)=$(WasiClang) </_ToolchainMissingPaths>
    </PropertyGroup>

    <PropertyGroup>
      <_ToolchainMissingErrorMessage Condition="'$(WASI_SDK_PATH)' == '' and '$(WasiSdkRoot)' == ''">Could not find wasi-sdk. Install wasi-sdk and set %24(WASI_SDK_PATH) . It can be obtained from https://github.com/WebAssembly/wasi-sdk/releases</_ToolchainMissingErrorMessage>
      <_ToolchainMissingErrorMessage Condition="'$(_ToolchainMissingErrorMessage)' == '' and '$(_ToolchainMissingPaths)' != ''">Using WASI_SDK_PATH=$(WASI_SDK_PATH), cannot find $(_ToolchainMissingPaths) .</_ToolchainMissingErrorMessage>
      <_IsToolchainMissing Condition="'$(_ToolchainMissingErrorMessage)' != ''">true</_IsToolchainMissing>
    </PropertyGroup>

    <PropertyGroup>
      <WasiSdkBinPath Condition="'$(WasiSdkBinPath)' != ''">$([MSBuild]::NormalizeDirectory($(WasiSdkBinPath)))</WasiSdkBinPath>
      <_WasmLLVMPathForAOT>$(WasiSdkBinPath)</_WasmLLVMPathForAOT>
    </PropertyGroup>
  </Target>

  <Target Name="_PrepareForWasiBuildNative">
    <Error Condition="'$(_IsToolchainMissing)' == 'true'"
           Text="$(_ToolchainMissingErrorMessage) SDK is required for building native files." />

    <PropertyGroup>
      <_MonoAotCrossCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','wasi-wasm'))</_MonoAotCrossCompilerPath>
      <_WasmDefaultFlagsRsp>$([MSBuild]::NormalizePath($(_WasmRuntimePackSrcDir), 'wasi-default.rsp'))</_WasmDefaultFlagsRsp>
      <_WasmDefaultLinkFlagsRsp>$([MSBuild]::NormalizePath($(_WasmRuntimePackSrcDir), 'wasi-link.rsp'))</_WasmDefaultLinkFlagsRsp>
      <WasmNativeDebugSymbols Condition="'$(WasmNativeDebugSymbols)' == ''">true</WasmNativeDebugSymbols>
      <WasmLinkIcalls Condition="'$(WasmLinkIcalls)' == ''">$(WasmBuildNative)</WasmLinkIcalls>

      <_WasmICallTablePath>$(_WasmIntermediateOutputPath)icall-table.h</_WasmICallTablePath>
      <_WasmRuntimeICallTablePath>$(_WasmIntermediateOutputPath)runtime-icall-table.h</_WasmRuntimeICallTablePath>
      <_WasmPInvokeTablePath>$(_WasmIntermediateOutputPath)pinvoke-table.h</_WasmPInvokeTablePath>
      <_WasmInterpToNativeTablePath>$(_WasmIntermediateOutputPath)wasm_m2n_invoke.g.h</_WasmInterpToNativeTablePath>
      <_WasmPInvokeHPath>$(_WasmRuntimePackIncludeDir)wasm\pinvoke.h</_WasmPInvokeHPath>
      <_DriverGenCPath>$(_WasmIntermediateOutputPath)driver-gen.c</_DriverGenCPath>
      <DisableParallelAot Condition="'$(DisableParallelAot)' == ''">false</DisableParallelAot>
      <DisableParallelEmccCompile Condition="'$(DisableParallelEmccCompile)' == ''">$(DisableParallelAot)</DisableParallelEmccCompile>

      <_DriverGenCNeeded Condition="'$(_DriverGenCNeeded)' == '' and '$(_WasmShouldAOT)' == 'true'">true</_DriverGenCNeeded>

      <_WasmDevel Condition="'$(_WasmDevel)' == '' and '$(WasmBuildNative)' == 'true' and '$(Configuration)' == 'Debug'">true</_WasmDevel>

      <!--<_EmccAssertionLevelDefault Condition="'$(_EmccAssertionLevelDefault)' == ''">0</_EmccAssertionLevelDefault>-->
      <_WasiClangOptimizationFlagDefault Condition="'$(_WasmDevel)' == 'true'">-O0</_WasiClangOptimizationFlagDefault>
      <_WasiClangOptimizationFlagDefault Condition="'$(_WasiClangOptimizationFlagDefault)' == '' and '$(Configuration)' == 'Debug' and '$(WasmBuildingForNestedPublish)' != 'true'">-O1</_WasiClangOptimizationFlagDefault>
      <_WasiClangOptimizationFlagDefault Condition="'$(_WasiClangOptimizationFlagDefault)' == ''">-Oz</_WasiClangOptimizationFlagDefault>

      <WasiClangCompileOptimizationFlag Condition="'$(WasiClangCompileOptimizationFlag)' == ''">$(_WasiClangOptimizationFlagDefault)</WasiClangCompileOptimizationFlag>
      <WasmCompileOptimizationFlag>$(WasiClangCompileOptimizationFlag)</WasmCompileOptimizationFlag>
      <WasiClangLinkOptimizationFlag    Condition="'$(WasiClangLinkOptimizationFlag)' == '' and '$(Configuration)' == 'Release'">-O2</WasiClangLinkOptimizationFlag>
      <WasiClangLinkOptimizationFlag    Condition="'$(WasiClangLinkOptimizationFlag)' == ''"   >$(WasiClangCompileOptimizationFlag)</WasiClangLinkOptimizationFlag>
      <WasmLinkOptimizationFlag>$(WasiClangLinkOptimizationFlag)</WasmLinkOptimizationFlag>

      <_WasmCompileRsp>$(_WasmIntermediateOutputPath)wasi-compile.rsp</_WasmCompileRsp>
      <_WasmCompileOutputMessageImportance Condition="'$(WasiClangVerbose)' == 'true'">Normal</_WasmCompileOutputMessageImportance>
      <_WasmCompileOutputMessageImportance Condition="'$(WasiClangVerbose)' != 'true'">Low</_WasmCompileOutputMessageImportance>

      <_WasmCompileBitcodeRsp>$(_WasmIntermediateOutputPath)wasi-compile-bc.rsp</_WasmCompileBitcodeRsp>
      <_WasmLinkRsp>$(_WasmIntermediateOutputPath)clang-link.rsp</_WasmLinkRsp>

       <!--TODOWASI this needs similar AOT logic as EMCC in https://github.com/dotnet/runtime/pull/80507-->
      <WasmInitialHeapSize Condition="'$(WasmInitialHeapSize)' == ''">52428800</WasmInitialHeapSize>
      <WasmClang>$(WasiClang)</WasmClang>
    </PropertyGroup>

    <ItemGroup>
      <WasiAfterRuntimeLoadedDeclarations Include="@(WasiAfterRuntimeLoaded->'void %(Identity)();')" />
      <WasiAfterRuntimeLoadedCalls Include="@(WasiAfterRuntimeLoaded->'%(Identity)();')" />

      <_WasmCommonIncludePaths Include="$(_WasmIntermediateOutputPath.TrimEnd('\/'))" />
      <_WasmCommonIncludePaths Include="$(_WasmRuntimePackIncludeDir)mono-2.0" />
      <_WasmCommonIncludePaths Include="$(_WasmRuntimePackIncludeDir)wasm" />
    </ItemGroup>

    <ItemGroup Condition="'$(OS)' == 'Windows_NT'">
      <!-- Fixup on windows -->
      <_WasmCommonIncludePathsFixedUp Include="$([System.String]::new(%(_WasmCommonIncludePaths.Identity)).Replace('\', '/'))" />
      <_WasmCommonIncludePaths Remove="@(_WasmCommonIncludePaths)" />
      <_WasmCommonIncludePaths Include="@(_WasmCommonIncludePathsFixedUp)" />
    </ItemGroup>

    <ItemGroup>
      <_WasmLinkDependencies Remove="@(_WasmLinkDependencies)" />

      <_WasiClangCommonFlags Include="$(_DefaultWasiClangFlags)" />
      <_WasiClangCommonFlags Include="$(WasiClangFlags)" />
      <_WasiClangCommonFlags Include="--sysroot=&quot;$(WasiSdkRoot.Replace('\', '/'))/share/wasi-sysroot&quot;" />
      <_WasiClangCommonFlags Include="-g"                                Condition="'$(WasmNativeStrip)' == 'false'" />
      <_WasiClangCommonFlags Include="-v"                                Condition="'$(WasiClangVerbose)' != 'false'" />
      <!--<_WasiClangCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0"   Condition="'$(WasmEnableExceptionHandling)' == 'false'" />-->
      <!--<_WasiClangCommonFlags Include="-fwasm-exceptions"                 Condition="'$(WasmEnableExceptionHandling)' == 'true'" />-->
      <!--<_WasiClangCommonFlags Include="-msimd128"                         Condition="'$(WasmEnableSIMD)' == 'true'" />-->

      <_WasmCommonCFlags Include="-DGEN_PINVOKE=1" />
      <_WasmCommonCFlags Condition="'$(_WasmShouldAOT)' == 'true'"         Include="-DENABLE_AOT=1" />
      <_WasmCommonCFlags Condition="'$(_DriverGenCNeeded)' == 'true'"      Include="-DDRIVER_GEN=1" />
      <_WasmCommonCFlags Condition="'$(WasmSingleFileBundle)' == 'true'"   Include="-DWASM_SINGLE_FILE=1" />
      <_WasmCommonCFlags Condition="'$(InvariantGlobalization)' == 'true'" Include="-DINVARIANT_GLOBALIZATION=1" />
      <_WasmCommonCFlags Condition="'$(InvariantTimezone)' == 'true'"      Include="-DINVARIANT_TIMEZONE=1" />
      <_WasmCommonCFlags Condition="'$(WasmLinkIcalls)' == 'true'"         Include="-DLINK_ICALLS=1" />
      <_WasiClangCFlags Include="@(_WasmCommonCFlags)" />

      <_WasiClangCFlags Include="&quot;-I%(_WasmCommonIncludePaths.Identity)&quot;" />
      <_WasiClangCFlags Include="-I&quot;$(MicrosoftNetCoreAppRuntimePackRidNativeDir.Replace('\', '/'))include&quot;" />

      <_WasiClangCFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" />

      <_WasiClangCFlags Condition="'@(WasiAfterRuntimeLoadedDeclarations)' != ''"
                         Include="-D WASI_AFTER_RUNTIME_LOADED_DECLARATIONS=&quot;@(WasiAfterRuntimeLoadedDeclarations, ' ')&quot;" />
      <_WasiClangCFlags Condition="'@(WasiAfterRuntimeLoadedCalls)' != ''"
                         Include="-D WASI_AFTER_RUNTIME_LOADED_CALLS=&quot;@(WasiAfterRuntimeLoadedCalls, ' ')&quot;" />

      <_WasiClangLDFlags Include="$(WasiClangLinkOptimizationFlag)" />
      <_WasiClangLDFlags Include="@(_WasiClangCommonFlags)" />
    </ItemGroup>

    <ItemGroup>
      <_DriverCDependencies Include="$(_WasmPInvokeHPath);$(_WasmICallTablePath)" />
      <_DriverCDependencies Include="$(_DriverGenCPath)" Condition="'$(_DriverGenCNeeded)' == 'true'" />

      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)pinvoke.c"
                               Dependencies="$(_WasmPInvokeHPath);$(_WasmPInvokeTablePath)" />
      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)driver.c"
                               Dependencies="@(_DriverCDependencies)" />
      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)runtime.c"
                               Dependencies="@(_DriverCDependencies)" />
      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)main.c" />
      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)stubs.c" />
      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)synthetic-pthread.c" />

      <_WasmRuntimePackSrcFile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" />
    </ItemGroup>

    <ItemGroup Condition="'$(WasmSingleFileBundle)' == 'true'">
      <_WasmBundleItem
                Include="@(_WasmAssembliesInternal)"
                BundleRegistrationFunctionName="mono_register_assemblies_bundle"
                BundleFile="wasi_bundled_assemblies.o" />

      <!-- FIXME: always included? -->
      <_WasmBundleItem
                Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"
                BundleRegistrationFunctionName="mono_register_icu_bundle"
                BundleFile="wasi_bundled_icu.o" />

      <!-- FIXME: if it is missing? -->
      <_WasmBundleItem
                Include="$(_ParsedRuntimeConfigFilePath)"
                BundleRegistrationFunctionName="mono_register_runtimeconfig_bin"
                BundleFile="wasi_bundled_runtimeconfig_bin.o" />
    </ItemGroup>

    <Error Text="Could not find NativeFileReference %(NativeFileReference.Identity)" Condition="'%(NativeFileReference.Identity)' != '' and !Exists(%(NativeFileReference.Identity))" />
    <Error Condition="'$(WasmSingleFileBundle)' == 'true' and '$(WasmMainAssemblyFileName)' == ''" Text="%24(WasmMainAssemblyFileName) is not set" />
  </Target>

  <Target Name="_WasiWriteCompileRsp" BeforeTargets="_WasmWriteRspForCompilingNativeSourceFiles">
    <ItemGroup>
      <_WasmCFlags Include="@(_WasiClangCFlags)" />
      <_WasmCFlags Include="$(WasiClangExtraCFlags)" />
    </ItemGroup>
  </Target>

  <!-- FIXME: merge with some other target -->
  <Target Name="_WasiBeforeWriteRspForCompilingBitcodeRsp" BeforeTargets="_WasmWriteRspForCompilingBitcode">
    <ItemGroup>
      <_BitcodeLDFlags Include="@(_WasiClangLDFlags)" />
      <_BitcodeLDFlags Include="$(WasiClangExtraBitcodeLDFlags)" />
    </ItemGroup>
  </Target>

  <Target Name="_WasiWriteRspForLinking"
          DependsOnTargets="_WasmSelectRuntimeComponentsForLinking;_WasiGetWasiOutputFileName"
          BeforeTargets="_WasmWriteRspForLinking"
          Returns="@(_WasmLinkStepArgs)">

    <!-- Generate a file entrypoint_YourAssemblyName.c containing the dotnet_wasi_getentrypointassemblyname symbol.
       This means we don't have to hardcode the assembly name in main.c -->
    <PropertyGroup>
      <_WasiGetEntrypointCFile>$(_WasmIntermediateOutputPath)entrypoint_$(WasmMainAssemblyFileName).c</_WasiGetEntrypointCFile>
    </PropertyGroup>
    <WriteLinesToFile File="$(_WasiGetEntrypointCFile)"
              Overwrite="true"
              Condition="'$(WasmSingleFileBundle)' == 'true'"
              Lines="const char* dotnet_wasi_getentrypointassemblyname() { return &quot;$(WasmMainAssemblyFileName)&quot;%3B }"
              WriteOnlyWhenDifferent="true" />
    <WriteLinesToFile File="$(_WasiGetEntrypointCFile)"
              Overwrite="true"
              Condition="'$(WasmSingleFileBundle)' != 'true'"
              Lines="const char* dotnet_wasi_getentrypointassemblyname() { return &quot;managed/$(WasmMainAssemblyFileName)&quot;%3B }"
              WriteOnlyWhenDifferent="true" />
    <ItemGroup>
      <FileWrites Include="$(_WasiGetEntrypointCFile)" />
    </ItemGroup>

    <PropertyGroup>
      <!-- FIXME: eh case -->
      <_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-wasm.a</_WasmEHLib>
      <!--<_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-js.a</_WasmEHLib>-->
      <!--<_WasmEHLibToExclude Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-js.a</_WasmEHLibToExclude>-->
      <_WasmEHLibToExclude Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-wasm.a</_WasmEHLibToExclude>
      <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-simd.a</_WasmSIMDLib>
      <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-nosimd.a</_WasmSIMDLib>
      <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-simd.a</_WasmSIMDLibToExclude>
      <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-nosimd.a</_WasmSIMDLibToExclude>
    </PropertyGroup>

    <ItemGroup>
      <!-- order matters -->
      <_WasmNativeFileForLinking Include="%(_BitcodeFile.ObjectFile)" />
      <!--<_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompile.ObjectFile)" />-->
      <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" />
      <_MonoRuntimeComponentDontLink Include="wasm-bundled-timezones.a" Condition="'$(InvariantTimezone)' == 'true'"/>

      <_WasmNativeFileForLinking
          Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a"
          Exclude="@(_MonoRuntimeComponentDontLink->'$(MicrosoftNetCoreAppRuntimePackRidNativeDir)%(Identity)')" />
      <_WasmNativeFileForLinking Condition="'$(_WasmEHLib)' != ''" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLib)" />
      <_WasmNativeFileForLinking Condition="'$(_WasmSIMDLib)' != ''" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLib)" />
      <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLibToExclude)" />
      <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLibToExclude)" />

      <_WasmNativeFileForLinking Include="$(WasiSysRoot)\lib\wasm32-wasi\libc++.a" />
      <_WasmNativeFileForLinking Include="$(WasiSysRoot)\lib\wasm32-wasi\libc++abi.a" />

      <_WasmNativeFileForLinking Include="@(NativeFileReference)" />
    </ItemGroup>

    <ItemGroup>
      <_WasiClangXLinkerFlags Include="--initial-memory=$(WasmInitialHeapSize)" />

      <_WasiFilePathForFixup Include="$(_WasiGetEntrypointCFile)" />
      <_WasiFilePathForFixup Include="@(_WasmObjectFilesForBundle)" />
      <_WasiFilePathForFixup Include="@(_WasmNativeFileForLinking)" />

      <_WasmLinkDependencies Include="@(_WasiFilePathForFixup)" />

      <_WasiLinkStepArgs Condition="'$(OS)' == 'Windows_NT'" Include="&quot;$([System.String]::new(%(_WasiFilePathForFixup.Identity)).Replace('\', '/'))&quot;" />
      <_WasiLinkStepArgs Condition="'$(OS)' != 'Windows_NT'" Include="@(_WasiFilePathForFixup -> '&quot;%(Identity)&quot;')" />

      <_WasiLinkStepArgs Include="-Wl,--export=malloc,--export=free,--export=__heap_base,--export=__data_end" />
      <!-- keep in sync with src\mono\wasi\wasi.proj -->
      <_WasiLinkStepArgs Include="-Wl,-z,stack-size=8388608,-lwasi-emulated-process-clocks,-lwasi-emulated-signal,-lwasi-emulated-mman"/>
      <_WasiLinkStepArgs Include="-Wl,-s" Condition="'$(WasmNativeStrip)' == 'true'"/>

      <_WasiLinkStepArgs Include="&quot;@$(_WasmDefaultLinkFlagsRsp.Replace('\', '/'))&quot;" />
      <_WasiLinkStepArgs Include="@(_WasiClangXLinkerFlags -> '-Xlinker %(Identity)', ' ')" />
      <_WasiLinkStepArgs Include="@(_WasiClangLDFlags)" />

      <_WasiLinkStepArgs Include="-o &quot;$(_WasiOutputFileName.Replace('\', '/'))&quot;" />

      <_WasmLinkStepArgs Include="@(_WasiLinkStepArgs)" />
    </ItemGroup>
  </Target>

  <Target Name="_WasiLinkDotNet"
          Inputs="@(_WasmLinkDependencies);$(_WasmDefaultsFlagsRsp);$(_WasmDefaultLinkFlagsRsp);$(_WasmLinkRsp)"
          Outputs="$(_WasiOutputFileName)"
          Returns="@(FileWrites)"
          DependsOnTargets="_WasiWriteRspForLinking">

    <Message Text="Linking for initial memory %24(WasmInitialHeapSize)=$(WasmInitialHeapSize) bytes. Set this msbuild property to change the value." Importance="High" />
    <Message Text="Linking with $(WasiClang) with $(WasmLinkOptimizationFlag). This may take a while ..." Importance="High" />

    <Message Importance="High" Text="Performing WASI SDK build: &quot;$(WasiClang)&quot; &quot;$(_WasmLinkRsp)&quot;" />
    <Exec Command="&quot;$(WasiClang)&quot; &quot;@$(_WasmLinkRsp)&quot;" />

    <CallTarget Targets="_RunWasmOptPostLink" Condition="'$(WasmRunWasmOpt)' == 'true'" />

    <!-- FIXME: this will be done by the bundler -->
    <Copy SourceFiles="$(_WasiOutputFileName)" DestinationFolder="$(WasmAppDir)" />
    <ItemGroup>
      <FileWrites Include="$(_WasiOutputFileName)" />
    </ItemGroup>
  </Target>

  <Target Name="_WasiGetWasiOutputFileName">
    <Error Condition="'$(WasmSingleFileBundle)' == 'true' and '$(WasmMainAssemblyFileName)' == ''" Text="%24(WasmMainAssemblyFileName) is not set" />
    <PropertyGroup>
      <_WasiOutputFileName Condition="'$(WasmSingleFileBundle)' == 'true'">$([System.IO.Path]::GetFileNameWithoutExtension('$(WasmMainAssemblyFileName)')).wasm</_WasiOutputFileName>
      <_WasiOutputFileName Condition="'$(WasmSingleFileBundle)' != 'true'">dotnet.wasm</_WasiOutputFileName>
      <_WasiOutputFileName Condition="'$(_WasiOutputFileName)' != ''">$([System.IO.Path]::Combine($(_WasiIntermediateOutputPath), $(_WasiOutputFileName)))</_WasiOutputFileName>
    </PropertyGroup>

    <Error Condition="'$(_WasiOutputFileName)' == ''" Text="Could not determine $(_WasiOutputFileName)" />
  </Target>

  <Target Name="_CheckToolchainIsExpectedVersion" />

  <Target Name="_GenerateRunWasmtimeScript">
    <PropertyGroup>
      <WasmRunWasmtimeScriptPath Condition="'$(WasmRunWasmtimeScriptPath)' == ''">$(WasmAppDir)run-wasmtime.sh</WasmRunWasmtimeScriptPath>
      <_ScriptContent Condition="'$(WasmSingleFileBundle)' == 'true'">wasmtime run $([System.IO.Path]::GetFileNameWithoutExtension($(WasmMainAssemblyFileName))).wasm $*</_ScriptContent>
      <_ScriptContent Condition="'$(WasmSingleFileBundle)' != 'true'">wasmtime run --dir . dotnet.wasm $([System.IO.Path]::GetFileNameWithoutExtension($(WasmMainAssemblyFileName))) $*</_ScriptContent>
    </PropertyGroup>

    <Error Condition="'$(WasmMainAssemblyFileName)' == ''" Text="%24(WasmMainAssemblyFileName) property needs to be set for generating $(WasmRunWasmtimeScriptPath)." />
    <WriteLinesToFile
      File="$(WasmRunWasmtimeScriptPath)"
      Lines="$(_ScriptContent)"
      Overwrite="true" />

    <ItemGroup>
      <FileWrites Include="$(WasmRunWasmtimeScriptPath)" />
    </ItemGroup>

    <Exec Condition="'$(OS)' != 'Windows_NT'" Command="chmod a+x &quot;$(WasmRunWasmtimeScriptPath)&quot;" />
  </Target>

  <Target Name="_WasmGenerateNodeScripts">
    <PropertyGroup>
      <_WasmNodeJSPath>$(WasmAppDir)node.mjs</_WasmNodeJSPath>
      <_WasmNodeJSContents><![CDATA[
import { readFile } from 'node:fs/promises';
import { WASI } from 'wasi';
import { argv, env } from 'node:process';

const wasi = new WASI({
  version: 'preview1',
  args: argv.slice(1),
  env,
  preopens: {
    '/': '.',
    '/managed': './managed',
  },
});

const wasm = await WebAssembly.compile(
  await readFile(new URL('./dotnet.wasm', import.meta.url)),
);
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());

wasi.start(instance);
]]></_WasmNodeJSContents>
      <_WasmNodeScriptPath>$(WasmAppDir)run-node.sh</_WasmNodeScriptPath>
      <_WasmNodeScriptContents>node --experimental-modules --experimental-wasm-modules node.mjs $([System.IO.Path]::GetFileNameWithoutExtension($(WasmMainAssemblyFileName))) $*</_WasmNodeScriptContents>
    </PropertyGroup>

    <WriteLinesToFile
      File="$(_WasmNodeJSPath)"
      Lines="$(_WasmNodeJSContents)"
      Overwrite="true" />

    <WriteLinesToFile
      File="$(_WasmNodeScriptPath)"
      Lines="$(_WasmNodeScriptContents)"
      Overwrite="true" />
    <Exec Condition="'$(OS)' != 'Windows_NT'" Command="chmod a+x &quot;$(_WasmNodeScriptPath)&quot;" />
  </Target>

  <!--<Target Name="_WasmCalculateInitialHeapSize" />-->
</Project>
